package com.qidian.mes.sys.interceptors;

import com.qidian.mes.pojo.OptionLog;
import com.qidian.mes.sys.annotations.OptionLogAnno;
import com.qidian.mes.sys.service.OptionLogService;
import com.qidian.mes.util.Tools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * @Author 戴着假发的程序员
 * @Company 起点编程
 * @Description
 * @Time 2024/4/7 12:00
 */
@Component
@ControllerAdvice // Advice的注解标记
public class OptionLogInterceptor extends RequestBodyAdviceAdapter implements HandlerInterceptor, ResponseBodyAdvice {
    @Autowired
    private OptionLogService optionLogService;

    private ThreadLocal<String> responseBodyTl = new ThreadLocal<>();
    private ThreadLocal<String> requestBodyTl = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 转换handler
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 产生一个OptionLog对象
        OptionLog log = new OptionLog();
        // 需要的信息:
        // 1. 模块名称
        String module = getModule(handlerMethod);
        log.setModule(module);
        // 2. 操作方法
        log.setOptionMethod(method.getName());
        // 3. 操作参数
        String requestParam = getRequestParam(request);
        log.setRequestParam(requestParam);
        // 4. 客户端IP
        log.setClientIp(request.getRemoteAddr());
        // 5. 异常信息
        log.setExceptionMessage(ex != null ? ex.getMessage() : "");
        // 6.用户编号
        log.setUserId(1L);
        // 7.请求url
        log.setRequestUrl(request.getRequestURI());
        // 8.请求方法
        log.setRequestMethod(request.getMethod());
        // 9.响应结果
        //从对应的ThreadLocal中获取相应体
        log.setResponseResult(responseBodyTl.get());

        System.out.println(log);
        optionLogService.saveLog(log);
    }

    /**
     * 获取请求参数
     * @param request
     * @return
     */
    private String getRequestParam(HttpServletRequest request) {
        String json = null;
        // 正常的请求参数可以通过getParameterMap获取
        Map<String, String[]> parameterMap = request.getParameterMap();
        if(parameterMap.size() == 0){
            // 请求参数在请求体中
            json = requestBodyTl.get();
        }else{
            // 将map转换为JSON返回
            json = Tools.object2json(parameterMap);
        }
        return json;
    }



    /**
     * 通过反射获取模块信息
     * @return
     */
    private String getModule(HandlerMethod handlerMethod){
        String module = "";
        // 获取bean  这里的bean就是我们的controller对象
        Object bean = handlerMethod.getBean();
        // 获取method  这里的method就是我们增强的方法
        Method method = handlerMethod.getMethod();
        // 获取类上方的注解
        OptionLogAnno annotation = bean.getClass().getAnnotation(OptionLogAnno.class);
        if (annotation != null){
            module = annotation.module();
        }
        // 获取方法上方的注解
        annotation = method.getAnnotation(OptionLogAnno.class);
        if (annotation != null){
            module = module + "/" + annotation.module();
        }
        if(!Tools.isBlank(module)){
            return module;
        }else {
            return "这个程序员很懒,没有写module注解";
        }
    }

    // ResponseBodyAdvice中的方法
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        // 支持监听响应  拦截所有的响应
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 相应体  body
        // 将body转换为JSON放入对应的ThreadLocal
        responseBodyTl.set(Tools.object2json(body));
        return body;
    }
    // requestBodyAdvice的实现
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 拦截所有的请求体
        return true;
    }


    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 这里就有请求体了,将请求体放入对应的ThreadLocal
        requestBodyTl.set(Tools.object2json(body));
        return body;
    }
}
